package com.os.opencv.java.chapter12;

import org.opencv.core.*;
import org.opencv.highgui.HighGui;
import org.opencv.imgproc.Imgproc;

import java.util.Random;

public class Kmeans {

    public static void main(String[] args) {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

        //3个集中点的数量
        int num1 = 30;
        int num2 = 30;
        int num3 = 30;
        int num = num1 + num2 + num3;

        Mat pts = new Mat(num, 1, CvType.CV_32FC2);
        float[] ptData = new float[(int) (num * pts.channels())];

        //随机获取第一个点集的坐标位置
        Random r = new Random();
        for(int i=0; i<num1; i++){
            ptData[2*i] = r.nextInt(100) + 100;
            ptData[2*i + 1] = r.nextInt(100) + 100;
        }

        //随机获取第二个点集的坐标位置
        for(int i=num1; i<num1+num2; i++){
            ptData[2*i] = r.nextInt(100) + 300;
            ptData[2*i + 1] = r.nextInt(100) + 400;
        }

        //随机获取第三个点集的坐标位置
        for(int i=num1+num2; i<num; i++){
            ptData[2*i] = r.nextInt(100) + 400;
            ptData[2*i+1] = r.nextInt(100) + 100;
        }

        //将点集数据入矩阵
        pts.put(0,0,ptData);

        //用k均值算法将点集聚类
        Mat labels = new Mat();
        Mat centers = new Mat(3,3,CvType.CV_32F);
        TermCriteria criteria = new TermCriteria(TermCriteria.COUNT + TermCriteria.EPS, 10, 0.1);
        Core.kmeans(pts, 3, labels, criteria, 3, Core.KMEANS_PP_CENTERS, centers);

        //用于显示结果的图像或颜色
        Mat dst = Mat.zeros(600, 600, CvType.CV_8UC3);

        //获取点集的标签数据
        int[] labelData = new int[(int)(num*labels.channels())];
        labels.get(0,0,labelData);

        //将点集用圆圈画出，并且不同点集用不同颜色
        for(int i=0; i<num; i++){
            int index = labelData[i];
            int x = (int)ptData[2*i];
            int y = (int)ptData[2*i + 1];
            if(index == 0){
                Imgproc.circle(dst, new Point(x,y), 3, new Scalar(255,0,0), -1);
            }else if(index == 1){
                Imgproc.circle(dst, new Point(x, y), 3, new Scalar(0,255,0), -1);
            }else{
                Imgproc.circle(dst, new Point(x, y), 3, new Scalar(0,0,255), -1);
            }
        }

        //用每个聚类的中心为圆心画圆
        float[] centerData = new float[6];
        centers.get(0,0,centerData);
        for(int i=0; i<3; i++){
            double x = centerData[2*i];
            double y = centerData[2*i+1];
            Imgproc.circle(dst, new Point(x,y), 50, new Scalar(255,255,255), 1);
        }

        //在屏幕上显示图像分割结果
        HighGui.imshow("kmeans", dst);
        HighGui.waitKey(0);

        System.exit(0);
    }
}
